﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CrmContacto.Contracts;
using CrmContacto.Data;
using Web.Framework.Svc;
using System.Net.Mail;
using System.IO;
using CrmContacto.Contracts.Enums;
using Web.Framework.Translate;
using System.Transactions;
using CrmContacto.Services.Classes;
using System.Configuration;
using CrmContacto.Services.Common;
using System.Threading;
using CrmContacto.Services.Marketing.Promociones;
using CrmContacto.Contracts.Contracts.Search;
using CrmContacto.Contracts.Promociones;
using CrmContacto.Contracts.Contracts;
using Web.Framework.Helpers;

namespace CrmContacto.Services.Marketing
{
    public class PromocionDiaDelPadre2012Lacoste : PromocionStrategyBase, IPromocionStrategy
    {
        public string Nombre { get { return "PromocionDiaDelPadre2012Lacoste"; } set { } }

        public int EmpresaId { get; set; }

        private const string accionMarketingNombre = "DiaDelPadre2012";
        private const string htmlMailNombre = "LacosteDiaDelPadre2012.html";

        public PromocionResultado CrearPromocion(PtoVentaRegistroCliente customer, bool esNuevo)
        {
            PromocionResultado promocionResultado = new PromocionResultado();
            promocionResultado.ContinuarProcesando = true;
            promocionResultado.EnviarEmailDeBienvenida = true;

            // La promoción no incluye los siguientes locales
            //Alto Rosario - LACOSTE ROSARIO ALTO
            //Portal Rosario - LACOSTE ROSARIO PORTAL
            //Córdoba Shopping - LACOSTE CORDOBA ALTO
            //Patio Olmos - LACOSTE CORDOBA PATIO OLMOS
            //Garay mar del plata - LACOSTE MDP GARAY
            //Los Gallegos Mar del plata- LACOSTE MDP SHOPPING

            if (customer.PuntoDeVentaId != 149 &&
                customer.PuntoDeVentaId != 150 &&
                customer.PuntoDeVentaId != 155 &&
                customer.PuntoDeVentaId != 157 &&
                customer.PuntoDeVentaId != 158 &&
                customer.PuntoDeVentaId != 160)
            {
            // Si el contacto es nuevo creo la promoción
            bool sendEmail = false;
            DateTime hoy = DateTime.Now.Date;
            EmailInfoExtra emailInfo = new EmailInfoExtra();
            string cupon = string.Empty;
            if (esNuevo && customer.EmpresaId == 1) // Solo para lacoste
            {
                using (TransactionScope tScope = new TransactionScope())
                {
                    using (CrmContactoEntities ctx = new CrmContactoEntities())
                    {
                        // ESta promoción tiene todo hardcoded, mediante el nombre de la promoción
                        var dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(a => a.Nombre.Contains(accionMarketingNombre)).SingleOrDefault();
                        if (dbAccionDeMarketing != null)
                        {
                            //11) El descuento se puede usar a partir del lunes 18/6/2012 hasta el 14/07/2012 inclusive.
                            //12) La vigencia de la promoción es desde el lunes 11/6/2012 hasta el viernes 13/7/2012.
                            DateTime vigenciaDesde = new DateTime(2012, 6, 11);
                            DateTime vigenciaHasta = new DateTime(2012, 7, 13);
                            // Para la fecha de la acción, se registra el cupon
                            if (
                               vigenciaDesde <= hoy &&
                               vigenciaHasta >= hoy)
                            //if (dbAccionDeMarketing.FechaDesde.HasValue &&
                            //    dbAccionDeMarketing.FechaHasta.HasValue &&
                            //    dbAccionDeMarketing.FechaDesde.Value.Date <= hoy &&
                            //    dbAccionDeMarketing.FechaHasta.Value.Date >= hoy)
                            {
                                // La promoción es para ciertos puntos de venta, lo verifico
                                //if (dbAccionDeMarketing.PuntoDeVentas.Select(p => p.Id).Contains(customer.PuntoDeVentaId))
                                //{
                                DateTime now = DateTime.Now;
                                // Registrar el cupón y enviar un email al cliente
                                cupon = GenerarNumeroDeCupon(ctx, customer.EmpresaId);
                                // Creo el cupon para ese usuario
                                DbAccionDeMarketingCupone dbCupon = new DbAccionDeMarketingCupone();
                                ctx.DbAccionDeMarketingCupones.AddObject(dbCupon);
                                dbCupon.AccionDeMarketingId = dbAccionDeMarketing.Id;
                                dbCupon.CodigoCupon = cupon;
                                dbCupon.ContactoIdGenerado = customer.Id;
                                dbCupon.FechaGeneracion = now;
                                dbCupon.PuntoDeVentaIdGeneracion = customer.PuntoDeVentaId;
                                dbCupon.AuditFechaCreacion = now;
                                dbCupon.AuditUserNameCreacion = customer.UserName;
                                dbCupon.EmpresaId = customer.EmpresaId;

                                emailInfo.Promocion = dbAccionDeMarketing.Nombre;
                                emailInfo.Cupon = cupon;

                                List<DbContactoBitacora> bitacoraList = new List<DbContactoBitacora>();
                                AgregarBitacoraMensaje(bitacoraList, string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponGenerado"], cupon), customer.UserName, now);
                                bitacoraList.ForEach(b => { b.ContactoId = customer.Id; ctx.DbContactoBitacoras.AddObject(b); });

                                ctx.SaveChanges();
                                tScope.Complete();

                                sendEmail = true;
                                //}
                            }
                        }
                    }
                }

                if (sendEmail)
                {
                    promocionResultado.ContinuarProcesando = false;
                    promocionResultado.EnviarEmailDeBienvenida = false;

                    customer.ServiceMessage += "Se generó el cupón: " + cupon;
                    // Envío el email al cliente con el cupón                                       
                    SendEmailToCustomerInThread(customer, emailInfo);
                }
            }
            }

            return promocionResultado;
        }

        public void ValidarAlAsociarPromocion(PtoVentaRegistroCliente customer, bool esNuevo)
        {
            if (customer.EmpresaId == 1)
            {
                DateTime now = DateTime.Now.Date;
                DateTime dateNow = DateTime.Now;
                using (TransactionScope tScope = new TransactionScope())
                {
                    using (CrmContactoEntities ctx = new CrmContactoEntities())
                    {
                        foreach (var factura in customer.Facturas)
                        {
                            if (!String.IsNullOrEmpty(factura.Cupon) && !String.IsNullOrEmpty(factura.Factura))
                            {
                                factura.Cupon = factura.Cupon.ToUpper();
                                var dbCupon = ctx.DbAccionDeMarketingCupones.Where(c => c.EmpresaId == customer.EmpresaId && c.CodigoCupon == factura.Cupon).SingleOrDefault();
                                if (dbCupon != null)
                                {                                    
                                    if (dbCupon.AccionDeMarketing.FechaDesde.Value > now || dbCupon.AccionDeMarketing.FechaHasta.Value < now)
                                    {
                                        // el cupon está fuera de fecha
                                        throw new SvcBusinessException(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponFueraFecha"]);
                                    }

                                    if (dbCupon.AccionDeMarketing.PuntoDeVentas.Count > 0 && !dbCupon.AccionDeMarketing.PuntoDeVentas.Select(p => p.Id).Contains(customer.PuntoDeVentaId))
                                    {
                                        throw new SvcBusinessException(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponNoAplicaEstePDV"]);
                                    }

                                    // Existe un cupón válido para asignar, controlo que no esté en uso por el mismo tipo
                                    if (dbCupon.ContactoIdUtilizado.HasValue && dbCupon.AuditFechaModificacion != dateNow)
                                    {
                                        // El cupón ya fue utilizado
                                        throw new SvcBusinessException(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponUtilizado"]);
                                    }
                                    else
                                    {
                                        List<DbContactoBitacora> bitacoraList = new List<DbContactoBitacora>();
                                        // fuerzo la accion de marketing
                                        factura.AccionDeMarketingId = dbCupon.AccionDeMarketingId;

                                        // Ademas marco el cupon como utilizado                                                                                
                                        dbCupon.ContactoIdUtilizado = customer.Id;
                                        dbCupon.FechaUtilizacion = dateNow;
                                        dbCupon.PuntoDeVentaIdUtilizacion = customer.PuntoDeVentaId;
                                        dbCupon.AuditFechaModificacion = dateNow;
                                        dbCupon.AuditUserNameModificacion = customer.UserName;

                                        ctx.SaveChanges();                                      

                                        // Obtengo el contactoventa y asocio el cupon
                                        var dbCustomer = ctx.DbContactoes.Where(c => c.EmpresaId == customer.EmpresaId && c.Id == customer.Id).Single();
                                        var dbContactoVenta = dbCustomer.ContactoVentas.Where(v => v.NroFactura == factura.Factura && v.PuntoDeVentaId == customer.PuntoDeVentaId && v.FechaVenta.Date == now).Single();

                                        dbContactoVenta.CuponId = dbCupon.Id;
                                        
                                        // Se utilizó el cupon
                                        AgregarBitacoraMensaje(bitacoraList, string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponAceptado"], dbCupon.CodigoCupon, dbCupon.Contacto.Email, dbContactoVenta.NroFactura), customer.UserName, dateNow);
                                        bitacoraList.ForEach(b => { b.ContactoId = dbCustomer.Id; ctx.DbContactoBitacoras.AddObject(b); });

                                        // Informo que se utilizó el cupon en la bitacora del que lo generó
                                        // El cupon fue usado por XX el día YY en el PDV ZZ con la FC WW
                                        string contactoUtilizado = string.Empty;
                                        if(!String.IsNullOrEmpty(dbCupon.Contacto1.Email))
                                        {
                                            contactoUtilizado =  dbCupon.Contacto1.Email;
                                        }
                                        else
                                        {
                                            if(dbCupon.Contacto1.NroDocumento.HasValue)
                                            {
                                                contactoUtilizado = LocalizationProvider.Instance["Contacto.DocumentoShort"] + dbCupon.Contacto1.NroDocumento.Value.ToString();
                                            }
                                        }

                                        bitacoraList.Clear();
                                        AgregarBitacoraMensaje(bitacoraList, string.Format(LocalizationProvider.Instance["Pdv.BitacoraMsg.LacosteDiaDelPadre2012.CuponUsadoPor"], contactoUtilizado, now, dbCupon.PuntoDeVenta1.Nombre, dbContactoVenta.NroFactura), customer.UserName, dateNow);
                                        bitacoraList.ForEach(b => { b.ContactoId = dbCupon.ContactoIdGenerado; ctx.DbContactoBitacoras.AddObject(b); });                                         

                                        ctx.SaveChanges();
                                        customer.ServiceMessage += LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponUsadoConExito"];                                        
                                    }
                                }
                                else
                                {
                                    // El código de cupón no pertenece a ninguna promoción
                                    throw new SvcBusinessException(LocalizationProvider.Instance["Bo.Validacion.PromoDiaPadre2012.CuponNumeroInvalido"]);
                                }
                            }
                        }
                        
                        tScope.Complete();
                    }
                }
            }            
        }

        private string GenerarNumeroDeCupon(CrmContactoEntities ctx, int empresaId)
        {
            string cupon = string.Empty;
            bool creadoExitoso = false;
            while (!creadoExitoso)
            {
                cupon = Guid.NewGuid().ToString().ToUpperInvariant().Substring(0, 8);

                if (ctx.DbAccionDeMarketingCupones.Where(c => c.EmpresaId == empresaId && c.CodigoCupon == cupon).Count() == 0)
                {
                    creadoExitoso = true;
                }
            }

            return cupon;
        }

        private void SendEmailToCustomerInThread(PtoVentaRegistroCliente customer, object extra)
        {
            ContactoForEmail contactoForEmail = new ContactoForEmail();
            contactoForEmail.ContactoId = customer.Id;
            contactoForEmail.Email = customer.Email;
            contactoForEmail.EmpresaId = customer.EmpresaId;
            contactoForEmail.UserName = customer.UserName;
            contactoForEmail.Origen = (int)TipoContactoOrigen.PuntoDeVenta;

            EmailInThread emailInThread = new EmailInThread();
            emailInThread.Contacto = contactoForEmail;
            emailInThread.ConnectionString = ConfigurationManager.ConnectionStrings["CrmContactoEntities"].ConnectionString;
            emailInThread.ConfigurationsByCompany = ListsCrm.GetCompanyConfigurationKeyValues(customer.EmpresaId);
            emailInThread.Extras = extra;

            ThreadPool.QueueUserWorkItem(SendEmailToCustomer, emailInThread);
        }

        private void SendEmailToCustomer(object param)
        {
            EmailInThread emailInThread = (EmailInThread)param;
            EmailInfoExtra emailExtra = (EmailInfoExtra)emailInThread.Extras;

            ContactoForEmail customer = emailInThread.Contacto;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctxCrm = new CrmContactoEntities(emailInThread.ConnectionString))
                {
                    List<DbContactoBitacora> contactoBitacoraList = new List<DbContactoBitacora>();
                    DbContacto dbContacto = ctxCrm.DbContactoes.Where(c => c.Id == customer.ContactoId).Single();

                    DbEmpresa dbEmpresa = ctxCrm.DbEmpresas.Where(e => e.Id == customer.EmpresaId).Single();
                    try
                    {
                        SendMail(customer.Email, emailInThread.ConfigurationsByCompany, emailExtra);
                        AgregarBitacoraEmail(contactoBitacoraList, string.Format(LocalizationProvider.Instance["Pdv.BitacoraMsgEmailPromocionLacosteDiaDelPadre"], emailExtra.Promocion, emailExtra.Cupon), customer.UserName, DateTime.Now);
                    }
                    catch (Exception ex)
                    {

                        // obtener todo el mensaje de excepcion
                        string mensaje = GetExceptionMessage(ex);
                        //mensaje += GetExceptionStackTrace(ex);
                        AgregarBitacoraEmail(contactoBitacoraList, string.Format(LocalizationProvider.Instance["Pdv.BitacoraMsgEmailPromocionLacosteDiaDelPadreFallo"], emailExtra.Promocion, mensaje), customer.UserName, DateTime.Now);

                        // Si no puede enviar el email borro el cupon
                        //var dbCupon = ctxCrm.DbAccionDeMarketingCupones.Where(c => c.EmpresaId == customer.EmpresaId && c.CodigoCupon == emailExtra.Cupon).SingleOrDefault();
                        //ctxCrm.DbAccionDeMarketingCupones.DeleteObject(dbCupon);
                    }

                    foreach (DbContactoBitacora bitacora in contactoBitacoraList)
                    {
                        dbContacto.ContactoBitacoras.Add(bitacora);
                    }

                    ctxCrm.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public bool FiltrarPromocionEnPdv(CrmContactoEntities ctxCrm, DbAccionDeMarketing accionesDeMarketing, CampaniasActivasSearch search)
        {
            return false;
        }

        private static void SendMail(string emailAddress, Dictionary<string, string> configurations, EmailInfoExtra emailExtra)
        {
            string subject = configurations[EmpresaConfigurationKeys.MailBienvenidaSubject];

            string pathBody = Path.GetDirectoryName(configurations[EmpresaConfigurationKeys.PathMailBienvenida]);
            pathBody = Path.Combine(pathBody, htmlMailNombre);

            string body = File.ReadAllText(pathBody);
            body = body.Replace("##codigocupon##", emailExtra.Cupon);
            string from = configurations[EmpresaConfigurationKeys.MailBienvenidaFrom];
            string replayTo = configurations[EmpresaConfigurationKeys.MailBienvenidaReplyTo];
            string host = configurations[EmpresaConfigurationKeys.MailHost];
            string port = configurations[EmpresaConfigurationKeys.MailPort];

            MailMessage email = new MailMessage();
            email.To.Add(new MailAddress(emailAddress));
            email.Subject = "Bienvenido al mundo Lacoste. Disfruta un 15% en tu próxima compra";
            email.Body = body;
            email.From = new MailAddress(from);
            email.ReplyToList.Add(new MailAddress(replayTo));
            //email.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure | DeliveryNotificationOptions.OnSuccess;
            email.IsBodyHtml = true;

            SmtpClient client = new SmtpClient();
            client.Host = host;
            client.Port = Convert.ToInt32(port);
            client.DeliveryMethod = SmtpDeliveryMethod.Network;
            client.Send(email);
        }

        private static void AgregarBitacoraEmail(List<DbContactoBitacora> bitacoraList, string mensaje, string userName, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Email;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = now;
            bitacoraList.Add(dbContactoBitacora);
        }

        private static void AgregarBitacoraMensaje(List<DbContactoBitacora> bitacoraList, string mensaje, string userName, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Mensaje;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = now;
            bitacoraList.Add(dbContactoBitacora);
        }

        public ParticipantesSearchResult GetParticipantes(ParticipantesSearch searchParam)
        {
            ParticipantesSearchResult result = new ParticipantesSearchResult();
            List<ParticipantePromocion> clientes = new List<ParticipantePromocion>();

            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                ctxCrm.CommandTimeout = 300;
                int totalDeResultados = 0;
                IQueryable<DbContacto> query = null;

                //1) Se aplicará solo a los nuevos clientes registrados durante la duración de la promoción.
                var dbPromocion = ctxCrm.DbAccionDeMarketingPromocions.Where(p => p.Id == searchParam.PromocionId).Single();

                //DateTime? desde = dbPromocion.AccionDeMarketing.FechaDesde;
                //DateTime? hasta = dbPromocion.AccionDeMarketing.FechaHasta;

                //12) La vigencia de la promoción es desde el lunes 11/6/2012 hasta el viernes 13/7/2012.
                DateTime? desde = new DateTime(2012, 6, 11);
                DateTime? hasta = new DateTime(2012, 7, 13);

                query = ctxCrm.DbContactoes.FilterLogicalRemoved();

                List<int> contactoIdList = new List<int>();
                if (searchParam.EmailList.Count > 0)
                {
                    contactoIdList = ctxCrm.DbContactoes.Where(c => searchParam.EmailList.Contains(c.Email)).Select(c => c.Id).ToList();
                    query = query.Where(c => contactoIdList.Contains(c.Id));
                }

                query = query.Where(c => c.EmpresaId == searchParam.EmpresaId);
              
                
                if(desde.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion >= desde.Value);
                }

                 if(hasta.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion <= hasta.Value);
                }

                 if (searchParam.Desde.HasValue)
                 {
                      query = query.Where(c => c.AuditFechaCreacion >= searchParam.Desde.Value);
                 }
                
                if(searchParam.Hasta.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion <= searchParam.Hasta.Value);
                }                        

                // Hay dos tipos, los que se les generó cupón y los que no (por X motivo)
                if (searchParam.AplicaCuponId.HasValue)
                {
                    if (searchParam.AplicaCuponId.Value)
                    {
                        // Generaron cupón
                        query = query.Where(c => c.AccionDeMarketingCupones.Count() > 0);
                    }
                    else
                    {
                        query = query.Where(c => c.AccionDeMarketingCupones.Count() == 0);
                    }
                }
              
                totalDeResultados = query.Count();
                      
                result.TotalDeResultados = totalDeResultados;

                if (searchParam.PageSize != 0)
                {
                    query = query.OrderByWithParam(searchParam.SortingField, searchParam.SortIsAsc).AsQueryable();
                    query = query.Skip(searchParam.PageSkip).Take(searchParam.PageSize);
                }

                List<DbContacto> dbContactoList = query.ToList();

                result.PageIndex = searchParam.PageSkip;
                result.PageSize = searchParam.PageSize;

                foreach (DbContacto dbContacto in dbContactoList)
                {
                    ParticipantePromocion registro = new ParticipantePromocion();
                    CrmContactoAdminService.LoadCustomerVeryBasicInfo(dbContacto, registro);
                    // Cargo los cupones
                    StringBuilder builder = new StringBuilder();
                    string separador = string.Empty;
                    foreach (var dbCupon in dbContacto.AccionDeMarketingCupones)
                    {
                        builder.Append(separador);
                        separador = ", ";
                        builder.Append(dbCupon.CodigoCupon);
                    }

                    registro.Cupon = builder.ToString();

                    clientes.Add(registro);
                }
            }

            result.Resultados = clientes;

            return result;
        }
    }
}
